﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using LaunchMeNot.Core;
using System.Windows;
using LaunchMeNot.Properties;

namespace LaunchMeNot.Converters
{
    /// <summary>
    /// Performs the opposite of BoolToVisibilityConverter, converting True to Visibility.Collapsed and False to Visibility.Hidden
    /// </summary>
    public class BoolToInvertedVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            try {
                bool b = System.Convert.ToBoolean(value);
                if (b)
                    return System.Windows.Visibility.Collapsed;
                else
                    return System.Windows.Visibility.Visible;
            } catch {
                return 1;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Inverts a boolean value.
    /// </summary>
    public class BooleanInverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            try {
                bool b = (bool)value;
                return !b;
            } catch {
                return true;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Returns an image source indicationg whether an entry has been launched, is pending launch or is next to launch.
    /// </summary>
    public class EntryStatusConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (values == null || values.Length != 4)
                return null;
            try {
                double launchDelay = System.Convert.ToDouble(values[0]),
                       remaining = System.Convert.ToDouble(values[1]);
                bool isLaunched = System.Convert.ToBoolean(values[2]);
                string errorMessage = System.Convert.ToString(values[3]);
                BitmapImage img = new BitmapImage();
                img.BeginInit();
                if (!string.IsNullOrEmpty(errorMessage)) {
                    img.UriSource = new Uri("pack://application:,,,/Resources/Images/error_16.png");
                } else if (isLaunched) {
                    img.UriSource = new Uri("pack://application:,,,/Resources/Images/tick_16.png");
                } else if (launchDelay == remaining) {
                    img.UriSource = new Uri("pack://application:,,,/Resources/Images/arrow_right_grey_16.png");
                } else {
                    img.UriSource = new Uri("pack://application:,,,/Resources/Images/arrow_right_16.png");
                }
                img.CacheOption = BitmapCacheOption.Default;
                img.EndInit();
                return img;
            } catch {
                return null;
            }
        }
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a time (double value in seconds - values[0]) to a formatted string such as 3s based on the user's countdown format preference.
    /// Returns an empty string if the value is zero, or if the time remaining (values[1]) is the same (indicating the countdown for the item hasn't yet started).
    /// </summary>
    public class CountdownFormatConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (values == null || values.Length != 2)
                return null;
            try {
                double launchDelay = System.Convert.ToDouble(values[0]),
                       remaining = System.Convert.ToDouble(values[1]);
                if (remaining > 0 && remaining != launchDelay) {
                    try {
                        return remaining.ToString(WPFConfigurationManager.CountdownFormat);
                    } catch {
                        return remaining;
                    }
                } else {
                    return string.Empty;
                }
            } catch {
                return null;
            }
        }
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            {
                throw new NotImplementedException();
            }
        }
    }

    /// <summary>
    /// Converts an IStartupEntry (<c>value</c>) and the name of an entry type (<c>parameter</c>) to Visibility.Visible if the type of the entry is <b>different</b> to the name given
    /// in parameter, otherwise returns Visibility.Collapsed if the two are <b>the same</b>.
    /// </summary>
    public class EntryEqualityVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            try {
                if (value is IStartupEntry && parameter != null) {
                    IStartupEntry entry = (IStartupEntry) value;
                    StartupEntryType parameterType = (StartupEntryType) Enum.Parse(typeof(StartupEntryType), System.Convert.ToString(parameter), true);
                    return entry.EntryType == parameterType ? Visibility.Collapsed : Visibility.Visible;
                }
            } catch {
            }
            return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts an IStartupEntry (value) and the name of a StartupEntryType (parameter) to a ConvertEventArgs instance.
    /// </summary>
    public class EntryConversionConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            try {
                if(value is IStartupEntry && parameter != null) {
                    StartupEntryType conversionTargetType = (StartupEntryType) Enum.Parse(typeof(StartupEntryType), System.Convert.ToString(parameter), true);
                    return new ConvertEventArgs((IStartupEntry) value, conversionTargetType);
                }
            } catch {
            }
            return Visibility.Visible;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Returns various information (specified by <paramref name="parameter"/>) for a given StartupEntryType (<paramref name="value"/>)
    /// Parameter must be either 'icon', 'friendlyname' or 'path'
    /// </summary>
    public class EntryTypeInfoConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            try {
                StartupEntryType entryType = (StartupEntryType)Enum.Parse(typeof(StartupEntryType), (value ?? string.Empty).ToString(), true);
                string requiredField = (parameter ?? string.Empty).ToString().ToLowerInvariant();
                switch (requiredField) {
                    case "icon":
                        BitmapImage img = new BitmapImage();
                        img.BeginInit();
                        switch (entryType) {
                            case StartupEntryType.AllUsersStartup:
                            case StartupEntryType.CurrentUserStartup:
                                img.UriSource = new Uri("pack://application:,,,/Resources/Images/startup_16.png");
                                break;
                            case StartupEntryType.CurrentUserRun:
                            case StartupEntryType.LocalMachineRun:
                                img.UriSource = new Uri("pack://application:,,,/Resources/Images/registry_16.png");
                                break;
                            case StartupEntryType.LaunchMeNot:
                                img.UriSource = new Uri("pack://application:,,,/Resources/Images/launch_16.png");
                                break;
                        }
                        img.CacheOption = BitmapCacheOption.Default;
                        img.EndInit();
                        return img;
                    case "friendlyname":
                        switch (entryType) {
                            case StartupEntryType.AllUsersStartup:
                                return I18nUtils.GetString("Strings", "AllUsersStartupFolder", DispatcherPriority.Send);
                            case StartupEntryType.CurrentUserStartup:
                                return I18nUtils.GetString("Strings", "CurrentUserStartupFolder", DispatcherPriority.Send);
                            case StartupEntryType.CurrentUserRun:
                                return I18nUtils.GetString("Strings", "RegistryCurrentUserRun", DispatcherPriority.Send);
                            case StartupEntryType.LocalMachineRun:
                                return I18nUtils.GetString("Strings", "RegistryLocalMachineRun", DispatcherPriority.Send);
                            case StartupEntryType.LaunchMeNot:
                                return "LaunchMeNot";
                            default:
                                return I18nUtils.GetString("Strings", "Unknown");
                        }
                    case "path":
                        switch (entryType) {
                            case StartupEntryType.CurrentUserRun:
                                return "HKCU\\" + LaunchMeNotBLL.GetPath(entryType);
                            case StartupEntryType.LocalMachineRun:
                                return "HKLM\\"+ LaunchMeNotBLL.GetPath(entryType);
                            default:
                                return LaunchMeNotBLL.GetPath(entryType);
                        }
                }
                return string.Empty;
            } catch {
                return value;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Formats a search string with the name of an entry to search online.
    /// </summary>
    public class SearchOnlineConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            try {
                IStartupEntry entry = value as IStartupEntry;
                string searchUrl = System.Convert.ToString(parameter);
                if (entry != null && !string.IsNullOrEmpty(searchUrl)) {
                    string fileName = System.IO.Path.GetFileName(entry.Path);
                    return searchUrl.Replace("%1", fileName);
                }
            }catch {
            }
            return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Formats a number to show the number of entries (due to lack of binding support for StringFormat.
    /// </summary>
    public class ItemCountFormatter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            try {
                int numEntries = System.Convert.ToInt32(value);
                if (numEntries == 0) {
                    //return I18nUtils.GetString("Strings", "NoItems", DispatcherPriority.Send);
                    return LaunchMeNot.Core.I18nUtils.GetString("Strings", "NoItems");
                } else if (numEntries == 1) {
                    //return I18nUtils.GetString("Strings", "ItemCountFmt", DispatcherPriority.Send, numEntries.ToString());
                    return LaunchMeNot.Core.I18nUtils.GetString("Strings", "ItemCountFmt", numEntries.ToString());
                } else {
                    //return I18nUtils.GetString("Strings", "ItemsCountFmt", DispatcherPriority.Send, numEntries.ToString());
                    return LaunchMeNot.Core.I18nUtils.GetString("Strings", "ItemsCountFmt", numEntries.ToString());
                }
            } catch {
            }
            return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Provides a breakpoint for debugging
    /// </summary>
    public class DebugConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

}
